package com.sky.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.context.UserHolder;
import com.sky.dto.*;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.exception.BusinessException;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.ShoppingCartMapper;
import com.sky.result.PageBean;
import com.sky.service.AddressBookService;
import com.sky.service.OrderService;
import com.sky.service.ShoppingCartSerivce;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import com.sky.websocket.WebSocketServer;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
//@RequiredArgsConstructor //由lombok提供,替代@Autowired  但是需要使用final修饰注入的属性
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private AddressBookService addressBookService;
    @Autowired
    private ShoppingCartSerivce shoppingCartService;
    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private ShoppingCartMapper shoppingCartMapper;


    // 用户下单
    @Override
    public OrderSubmitVO save(Orders orders) {
        //1 根据地址id查询地址信息(复用之前的)
        Long addressBookId = orders.getAddressBookId();
        AddressBook addressBook = addressBookService.findById(addressBookId);
        if (addressBook == null) {
            throw new RuntimeException("地址信息有误");
        }
        //2 根据登录用户id查询目前的购物车(复用之前的查询购物车)
        List<ShoppingCart> shoppingCartList = shoppingCartService.findList();
        if (shoppingCartList == null || shoppingCartList.size() == 0) {
            throw new RuntimeException("购物车为空");
        }
        //3 将订单数据保存到orders表
        //3-1 补齐数据(拿前端给出的字段与数据库比较,数据库多出来的,就是要补齐的) 开心消消乐
        orders.setNumber(IdUtil.simpleUUID()); // 订单号:自己生成,要求唯一(不能大于32位)
        orders.setStatus(1); //订单状态: 待付款
        orders.setUserId(UserHolder.get()); // 下单用户
        orders.setOrderTime(LocalDateTime.now()); // 下单时间
        orders.setPayStatus(0); // 支付状态: 待支付
        orders.setPhone(addressBook.getPhone());// 收货人手机号(从地址表中获取)
        orders.setAddress(addressBook.getProvinceName() +
                addressBook.getCityName() + addressBook.getDistrictName()
                + addressBook.getDetail());// 收货地址(从地址表中获取)
        orders.setConsignee(addressBook.getConsignee());// 收货人(从地址表中获取)

        // 3-2 保存到数据库(订单表中)  主键返回
        ordersMapper.save(orders);

        //4 将购物车数据保存到order_detail表中
        //4-1 遍历购物车集合,获取每个菜品,保存到order_detail表中
        for(ShoppingCart shoppingCart : shoppingCartList){
            //4-2 购物项--订单详情（忽略id) 拷贝购物项
            OrderDetail orderDetail = BeanUtil.copyProperties(shoppingCart, OrderDetail.class, "id");
            //4-3 设置订单id
            orderDetail.setOrderId(orders.getId());
            //4-4 保存到数据库  保存到order_detail表中
            orderDetailMapper.save(orderDetail);
        }

        //5 清空购物车 (复用之前(昨天))
        shoppingCartService.clean();

        //6 返回订单数据
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                .id(orders.getId())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .build(); //则是个数据都是  返回数据里包含的
        return orderSubmitVO;



    }


    @Autowired
    private WebSocketServer webSocketServer;
    // 订单支付
    @Override
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO)  throws Exception{
        // 1.直接修改订单状态
        Orders ordersDB = ordersMapper.findByNumber(ordersPaymentDTO.getOrderNumber());
        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        ordersMapper.update(orders);

        //===================================通知商家: 新订单来了===========================//
        //1. 构建消息对象
        Map<String,Object> map =new HashMap<String,Object>();//构建一个map集合
        map.put("type",1);//1代表新订单
        map.put("orderId",ordersDB.getId());//订单id
        map.put("content","订单号：" + ordersPaymentDTO.getOrderNumber());//订单号
        //2 对象转JSON
        String json = JSON.toJSONString(map);
        //3. 调用websocket终端,发送消息给浏览器
        webSocketServer.sendToAllClient(json);
        //===================================通知商家: 新订单来了===========================//

        // 2. 返回一个空结果
        return new OrderPaymentVO();
    }

    // 分页查询历史订单
    @Override
    public PageBean findByPage(OrdersPageQueryDTO ordersPageQueryDTO) {
        // 1.开启分页
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());

        // 2.条件查询List<OederVO>查询
        List<OrderVO> list = ordersMapper.findList(ordersPageQueryDTO);
        Page<OrderVO> page = (Page<OrderVO>) list;// 强转一下

        //3. 遍历订单集合,封装获取每个订单的详细信息
        page.getResult().stream().forEach(orderVO -> {
            //3-1 调用orderDetailMapper根据订单id查询详情列表
            List<OrderDetail> detailList = orderDetailMapper.findByOrderId(orderVO.getId());
            //3-2 将detail封装到vo
            orderVO.setOrderDetailList(detailList);

            //3-3 新增订单明细拼接字符串(这是为达到管理端  订单搜索 而补充的)
            StringBuilder sb = new StringBuilder();// 创建一个可变字符串
            detailList.stream().forEach(detail -> {// 遍历集合,拼接字符串
                sb.append(detail.getName()).append("x").append(detail.getNumber()).append(";");
            });
            orderVO.setOrderDishes(sb.toString());// 设置订单菜品
        });

       /* if (CollectionUtil.isNotEmpty(page.getResult())) {
            for (OrderVO orderVO : page.getResult()) {
                //3-1 调用orderDetailMapper根据订单id查询详情列表
                List<OrderDetail> details = orderDetailMapper.findByOrderId(orderVO.getId());
                //3-2 将detail封装到vo
                orderVO.setOrderDetailList(details);
            }
        }
*/

        //4 返回
        return new PageBean(page.getTotal(), page.getResult());
    }

    // 查询订单详情
    @Override
    public OrderVO findById(Long id) {
        //1 根据订单id查询订单基本信息
        OrderVO orderVO = ordersMapper.findById(id);
        //2 根据订单id查询订单详情信息
        if (orderVO != null){
            List<OrderDetail> orderDetailList = orderDetailMapper.findByOrderId(id);
            //3 将订单详情信息封装到orderVO中
            orderVO.setOrderDetailList(orderDetailList);
        }
        return orderVO;
    }

    //取消订单
    @Override
    public void cancelById(Long id) {
        //1 根据订单id查询订单信息
        OrderVO orderVO = ordersMapper.findById(id);
        //2 判断订单状态
        if (orderVO.getStatus() > Orders.TO_BE_CONFIRMED) {//TO_BE_CONFIRMED==2
            // (3已接单 4派送中 5已完成 6已取消)
            throw new RuntimeException("订单无法取消,请联系商家");
        }
        //3 修改订单状态为已取消
        //3-1 构造修改对象
        Orders ordersUpdate = Orders.builder()
                .id(id)//订单id
                .status(Orders.CANCELLED)//订单状态: 已取消  CANCELLED==6
                .cancelReason("用户取消")//取消原因
                .cancelTime(LocalDateTime.now())//取消时间
                .build();//
        //3-2 如果是已支付的订单,需要发起微信退款请求
        if (orderVO.getPayStatus() == Orders.PAID) {//PAID==1
            try {
                //weChatPayUtil.refund(orderVO.getNumber(), orderVO.getNumber(), new BigDecimal(0.01), new BigDecimal(0.01));
                ordersUpdate.setPayStatus(2);//2退款
            } catch (Exception e) {
                throw new BusinessException("微信退款失败,联系商家");
            }
        }
        //3-3 执行修改
        ordersMapper.update(ordersUpdate);
    }

    // 再来一单
    @Override
    public void repetition(Long id) {
        //1 清理当前用户购物车
        shoppingCartService.clean();
        //2 根据订单id查询当前订单详情
        List<OrderDetail> orderDetailList = orderDetailMapper.findByOrderId(id);

        //3 将订单详情对象转为购物车对象
        if (CollectionUtil.isNotEmpty(orderDetailList)) {
            for (OrderDetail orderDetail : orderDetailList){
                //3-1 将订单详情对象转为购物车对象
                ShoppingCart shoppingCart = BeanUtil.copyProperties(orderDetail, ShoppingCart.class, "id");
                //3-2 补齐参数
                shoppingCart.setUserId(UserHolder.get());
                shoppingCart.setCreateTime(LocalDateTime.now());
                //3-3 保存到购物车表
                shoppingCartService.save(shoppingCart);
            }
        }
    }

    //各个状态的订单数量统计
    @Override
    public OrderStatisticsVO statistics() {
        //1 查询订单状态为待接单的数量  2
        Integer toBeConfirmed = ordersMapper.findCountStatus(Orders.TO_BE_CONFIRMED);
        //2 查询订单状态为待派送的数量 3
        Integer confirmed = ordersMapper.findCountStatus(Orders.CONFIRMED);
        //3 查询订单状态为配送中的数量 4
        Integer deliveryInProgress = ordersMapper.findCountStatus(Orders.DELIVERY_IN_PROGRESS);

        /*//查询各个状态  2待接单 3已接单 4派送中
        int toBeConfirmedCount = ordersMapper.findList(OrdersPageQueryDTO.builder().status(2).build()).size();
        int confirmedCount = ordersMapper.findList(OrdersPageQueryDTO.builder().status(3).build()).size();
        int deliveryInProgressCount = ordersMapper.findList(OrdersPageQueryDTO.builder().status(4).build()).size();*/
        //4 封装结果并返回VO
        return OrderStatisticsVO.builder()
                .toBeConfirmed(toBeConfirmed)
                .confirmed(confirmed)
                .deliveryInProgress(deliveryInProgress)
                .build();
    }


    // 接单 (把订单状态2 改为3 也只能 把订单状态2 改为3 所以要做判断)
    @Override
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        //1 根据id查询订单 信息
        OrderVO orderVO  = ordersMapper.findById(ordersConfirmDTO.getId());
        //2 判断订单状态是否为待接单
        if (orderVO.getStatus() != Orders.TO_BE_CONFIRMED) { // TO_BE_CONFIRMED==2
            throw new BusinessException("订单状态非待接单");
        }
        //3 修改订单状态为已接单
        Orders ordersUpdate = Orders.builder()
                .id(ordersConfirmDTO.getId())
                .status(Orders.CONFIRMED)   //Orders.CONFIRMED == 3 已接单
                .build();

        //4 执行修改
        ordersMapper.update(ordersUpdate); //复用之前就OK

    }

    //拒单 (把订单状态2 改为6 也只能 把订单状态2 改为6 所以要做判断  这是商户拒单)
    @Override
    public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
        //1 根据id查询订单信息
        OrderVO orderVO = ordersMapper.findById(ordersRejectionDTO.getId());
        //2 判断订单状态是否为待接单
        if (orderVO.getStatus() != Orders.TO_BE_CONFIRMED) { // TO_BE_CONFIRMED==2
            throw new BusinessException("订单状态非待接单");
        }
        //3 修改订单状态为已拒单
        Orders ordersUpdate = Orders.builder()
                .id(ordersRejectionDTO.getId()) //订单id
                .status(Orders.CANCELLED) //CANCELLED==6
                .cancelReason("商家拒单")//商户拒单原因
                .rejectionReason(ordersRejectionDTO.getRejectionReason())//商户拒绝原因
                .cancelTime(LocalDateTime.now())//取消时间
                .build();

        //4 若是已支付的订单,需要发起微信退款请求
        if (orderVO.getPayStatus() == Orders.PAID) {//PAID==1
            try {
                //weChatPayUtil.refund(orderVO.getNumber(), orderVO.getNumber(), new BigDecimal(0.01), new BigDecimal(0.01));
                ordersUpdate.setPayStatus(2);//2退款
            } catch (Exception e) {
                throw new BusinessException("微信退款失败,联系商家");
            }
        }

        //5 执行修改 (复用)
        ordersMapper.update(ordersUpdate);

    }

    // 取消订单 (- 商家取消订单时需要指定取消原因，使用OrdersCancelDTO接收
                  //- 只有订单处于`1待付款 2待接单 3已接单 4派送中 `状态时可以执行取消订单操作)
    @Override
    public void cancel(OrdersCancelDTO ordersCancelDTO) {
        //1 根据id查询订单信息
        OrderVO orderVO = ordersMapper.findById(ordersCancelDTO.getId());
        //2 判断订单状态是否为 待付款1  待接单2、待派送3、派送中4
        if (orderVO.getStatus() != Orders.PENDING_PAYMENT &&
            orderVO.getStatus() != Orders.TO_BE_CONFIRMED &&
            orderVO.getStatus() != Orders.CONFIRMED &&
            orderVO.getStatus() != Orders.DELIVERY_IN_PROGRESS) {

            throw new BusinessException("订单状态非待付款 待接单、待派送、派送中");
        }
        //3 修改订单状态为已取消
        Orders ordersUpdate = Orders.builder()
                .id(ordersCancelDTO.getId()) //订单id
                .status(Orders.CANCELLED) //CANCELLED==6
                .cancelReason(ordersCancelDTO.getCancelReason())//取消原因
                .cancelTime(LocalDateTime.now())//取消时间
                .build();

        //4 若是已支付的订单,需要发起微信退款请求
        if (orderVO.getPayStatus() == Orders.PAID) {//PAID==1
            try {
                //weChatPayUtil.refund(orderVO.getNumber(), orderVO.getNumber(), new BigDecimal(0.01), new BigDecimal(0.01));
                ordersUpdate.setPayStatus(2);//2退款
            } catch (Exception e) {
                throw new BusinessException("微信退款失败,联系商家");
            }
        }
        //5 执行修改 (复用)
        ordersMapper.update(ordersUpdate);

    }

    // 派送订单 (派送订单其实就是将订单状态修改为`派送中`  3 改为 4)
    @Override
    public void delivery(Long id) {
        //1 根据id查询订单信息
        OrderVO orderVO = ordersMapper.findById(id);
        //2 判断订单状态是否为已接单接单(待配送)
        if (orderVO.getStatus() != Orders.CONFIRMED) { // CONFIRMED==3
            throw new BusinessException("订单状态非待配送");
        }
        //3 修改订单状态为派送中(3 改为 4)
        Orders ordersUpdate = Orders.builder()
                .id(id) //订单id
                .status(Orders.DELIVERY_IN_PROGRESS) //DELIVERY_IN_PROGRESS==4
                .deliveryStatus(4)//派送状态 1派送中
                .deliveryTime(LocalDateTime.now())//派送时间
                .estimatedDeliveryTime(LocalDateTime.now().plusMinutes(30))//预计送达时间
                .build();

        //4 执行修改 (复用)
        ordersMapper.update(ordersUpdate);

    }


    // 完成订单 (完成订单其实就是将订单状态: 派送中修改为`已完成`  4 改为 5)
    @Override
    public void complete(Long id) {
        //1 根据id查询订单信息
        OrderVO orderVO = ordersMapper.findById(id);
        //2 判断订单状态是否为派送中
        if (orderVO.getStatus() != Orders.DELIVERY_IN_PROGRESS) { // DELIVERY_IN_PROGRESS==4
            throw new BusinessException("订单状态非配送中");
        }
        //3 修改订单状态为已完成
        Orders ordersUpdate = Orders.builder()
                .id(id) //订单id
                .status(Orders.COMPLETED) //COMPLETED==5
                .deliveryStatus(1)//派送状态 5已完成
                .deliveryTime(LocalDateTime.now())//送达时间
                .build();
        //4 执行修改 (复用)
        ordersMapper.update(ordersUpdate);
    }

    @Override
    public void reminderById(Long id) {
        //1. 查询订单
        OrderVO orderVO = ordersMapper.findById(id);
        if (orderVO == null || orderVO.getStatus() != 2){
            throw new BusinessException("状态错误");
        }
        //2. 构建消息对象
        Map<String,Object> map =new HashMap<String,Object>();
        map.put("type",2);
        map.put("orderId",id);
        map.put("content","订单号：" + orderVO.getNumber());
        //3 对象转JSON
        String json = JSON.toJSONString(map);
        //4. 调用websocket终端,发送消息给浏览器
        webSocketServer.sendToAllClient(json);
    }


}
